import env.Env as Env
from util import Ipc, PathUtil, Mail
import subprocess
import re
import os
import matplotlib.pyplot as plt
from io import BytesIO
import base64

# 设置 matplotlib 支持中文
plt.rcParams['font.family'] = 'SimHei'  # 使用黑体字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 配置 matplotlib 图表样式
plt.rcParams['figure.dpi'] = 300  # 提高图表分辨率


def warn_mail(host_info):
    """
    对每个主机的存储信息进行预警，当使用率超过80%时，发送邮件通知
    :param host_info: 主机信息列表
    :return:
    """
    # 用于存储超出使用率的挂载点信息
    warning_info = []
    for item in host_info:
        host_name = item["host_name"]
        storage_info = item["storage_info"]
        for storage_point in storage_info:
            storage = Env.get_host(host_name)["storage"]
            if storage is None:
                continue
            warn_mounted = storage["warn_mounted"]
            if warn_mounted is None:
                continue
            max_usage_percentage = storage["max_usage_percentage"]
            if max_usage_percentage is None:
                continue
            if storage_point["mount_point"] in warn_mounted:
                usage_percentage = storage_point["usage_percentage"]
                if usage_percentage > max_usage_percentage:
                    print(f"主机: {host_name}, 挂载点: {storage_point['mount_point']}, 使用率: {usage_percentage}%")
                    warning_info.append({
                        "host": host_name,
                        "mount_point": storage_point["mount_point"],
                        "total": storage_point["total"],
                        "used": storage_point["used"],
                        "usage_percentage": usage_percentage,
                    })
    # 生成 HTML 表格
    html_table = generate_warning_html_table(warning_info)
    # 这里可以添加发送邮件的代码，将 html_table 作为邮件内容发送
    # print(html_table)
    mailto = Env.get_mail_to()
    Mail.send_mail(mailto, "磁盘使用率预警", html_table)


def generate_warning_html_table(warning_info):
    """
    根据超出使用率的挂载点信息生成美观的 HTML 表格
    :param warning_info: 包含超出使用率挂载点信息的列表
    :return: 生成的 HTML 表格字符串
    """
    html = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>存储使用警告</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: #f4f4f9;
            padding: 20px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
            border-radius: 10px;
            overflow: hidden;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 12px 15px;
            text-align: left;
        }
        th {
            background-color: #007BFF;
            color: white;
            font-weight: 600;
        }
        tr:nth-child(even) {
            background-color: #f2f2f2;
        }
        tr:hover {
            background-color: #e0e0e0;
        }
    </style>
</head>
<body>
    <h2>存储使用警告</h2>
    <table>
        <tr>
            <th>主机</th>
            <th>挂载点</th>
            <th>总容量</th>
            <th>使用量</th>
            <th>使用比例</th>
        </tr>
    """
    for info in warning_info:
        html += f"""
        <tr>
            <td>{info["host"]}</td>
            <td>{info["mount_point"]}</td>
            <td>{info["total"]}</td>
            <td>{info["used"]}</td>
            <td>{info["usage_percentage"]}%</td>
        </tr>
        """
    html += """
    </table>
</body>
</html>
"""
    return html


def scan():
    """
    对所有的主机进行扫描，检查系统的磁盘，内存，cpu使用情况，并将结果按照ip进行分类，将结果生成一个html的图表
    :return:
    """
    host_info_list = []  # 主机信息
    for item in Env.get_host_list():
        host = item["host"]
        # 检查磁盘使用情况
        storage_info = get_storage_info(host)
        memory_info = get_memory_info(host)
        cpu_info = get_cpu_info(host)

        host_info = {
            "host_name": host,
            "storage_info": storage_info,
            "memory_info": memory_info,
            "cpu_info": cpu_info,
        }
        host_info_list.append(host_info)
    # 生成 HTML 报告
    html_content = generate_html(host_info_list)
    # 预警
    warn_mail(host_info_list)
    # 保存到log文件夹下
    rootlog = PathUtil.get_root_path() + "/report/"
    if not os.path.exists(rootlog):
        os.makedirs(rootlog)
    with open(rootlog + '/grap_report.html', 'w', encoding='utf-8') as f:
        f.write(html_content)


def get_storage_info(host):
    """
    获取 Linux 系统各挂载点的存储使用情况
    :return: 包含挂载点信息的列表，每个元素是一个字典，包含挂载点、总容量、已使用容量、可用容量和使用率
    """
    try:
        # 执行 df -h 命令获取存储信息
        cmd = "df -h"
        result = Ipc.shell_call_new(host=host, cmd=cmd)
        # 获取存储信息
        lines = result.splitlines()[1:]  # 跳过标题行
        storage_info = []
        for line in lines:
            parts = re.split(r'\s+', line)
            mount_point = parts[-1]
            total = parts[1]
            used = parts[2]
            available = parts[3]
            usage_percentage = parts[4].replace('%', '')
            storage_info.append({
                'mount_point': mount_point,
                'total': total,
                'used': used,
                'available': available,
                'usage_percentage': int(usage_percentage)
            })
        return storage_info
    except subprocess.CalledProcessError as e:
        print(f"执行命令时出错: {e}")
        return []


def get_memory_info(host):
    # 执行 df -h 命令获取存储信息
    cmd = "free -m"
    result = Ipc.shell_call_new(host=host, cmd=cmd)
    # 获取存储信息
    lines = result.splitlines()
    # 解析内存信息
    memory_parts = re.split(r'\s+', lines[1])
    total_memory = int(memory_parts[1])
    used_memory = int(memory_parts[2])
    available_memory = int(memory_parts[6])
    memory_usage_percentage = int((used_memory / total_memory) * 100)
    # 解析 Swap 信息
    swap_parts = re.split(r'\s+', lines[2])
    total_swap = int(swap_parts[1])
    used_swap = int(swap_parts[2])
    available_swap = int(swap_parts[3])
    swap_usage_percentage = int((used_swap / total_swap) * 100) if total_swap > 0 else 0
    return {
        'memory_usage_percentage': memory_usage_percentage,
        'available_memory_percentage': int((available_memory / total_memory) * 100),
        'swap_usage_percentage': swap_usage_percentage,
        'total_swap': total_swap,
        'used_swap': used_swap,
        'available_swap': available_swap
    }


def get_cpu_info(host):
    """
    获取指定主机 CPU 在不同状态下的时间占比
    :param host: 主机地址
    :param port: 端口号
    :param username: 用户名
    :param key_path: 密钥路径
    :return: 包含 CPU 不同状态时间占比的字典
    """
    try:
        # 执行 top -bn1 | grep "Cpu(s)" 命令获取 CPU 信息
        cmd = "top -bn1 | grep \"Cpu(s)\""
        result = Ipc.shell_call_new(host=host, cmd=cmd)
        # 解析 CPU 不同状态时间占比
        parts = re.findall(r'(\d+\.\d+) ([a-z]+)', result)
        cpu_info = {}
        for value, state in parts:
            cpu_info[state] = float(value)
        return cpu_info
    except subprocess.CalledProcessError as e:
        print(f"执行命令时出错: {e}")
        return {}


def generate_html(host_infos):
    """
    根据多个主机的存储、内存和 CPU 信息生成 HTML 文件
    :param host_infos: 包含多个主机信息的列表，每个元素是一个字典，包含主机名、存储信息、内存信息和 CPU 信息
    :return: HTML 内容
    """
    flush_interval = Env.get_flush_interval("storage")
    html = f"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="refresh" content="{flush_interval}">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>多服务器 Linux 存储、内存和 CPU 使用情况</title>
    <style>
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: #f4f4f9;
            margin: 20px;
        }}
        h1 {{
            text-align: center;
            color: #333;
            font-size: 24px;
            margin-bottom: 20px;
        }}
        .container {{
            display: flex;
            flex-direction: column;
            gap: 20px;
        }}
        .server-box {{
            background-color: #fff;
            border: none;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            padding: 20px;
            transition: box-shadow 0.3s ease;
        }}
        .server-box:hover {{
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
        }}
        h2 {{
            font-size: 20px;
            color: #333;
            margin-bottom: 15px;
        }}
        .info-container {{
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
        }}
        .info-column {{
            flex: 0 0 calc(50% - 10px); /* 两个一列，减去间距 */
            border: 1px solid #e0e0e0;
            border-radius: 4px;
            padding: 10px;
        }}
        h3 {{
            font-size: 16px;
            color: #555;
            margin-bottom: 10px;
        }}
        p {{
            font-size: 14px;
            color: #666;
            margin-bottom: 5px;
        }}
        img {{
            width: 100%;
            height: auto;
        }}
    </style>
</head>
<body>
    <h1>多服务器 Linux 存储、内存和 CPU 使用情况</h1>
    <div class="container">
    """

    for host_info in host_infos:
        host_name = host_info['host_name']
        storage_info = host_info['storage_info']
        memory_info = host_info['memory_info']
        cpu_info = host_info['cpu_info']

        html += f"""
        <div class="server-box">
            <h2>{host_name}</h2>
            <div class="info-container">
                <div class="info-column">
                    <h3>磁盘使用情况</h3>
        """
        # 生成磁盘使用情况直方图
        mount_points = [info['mount_point'] for info in storage_info]
        usage_percentages = [info['usage_percentage'] for info in storage_info]

        fig, ax = plt.subplots(figsize=(5, 4))  # 适当调整图表大小
        ax.bar(mount_points, usage_percentages, color='skyblue')
        ax.set_xlabel('挂载点', fontsize=10)
        ax.set_ylabel('使用率 (%)', fontsize=10)
        ax.set_title(f'{host_name} 磁盘使用情况', fontsize=10)
        ax.set_ylim(0, 100)

        img = BytesIO()
        plt.savefig(img, format='png', bbox_inches='tight')
        img.seek(0)
        plot_url = base64.b64encode(img.getvalue()).decode()

        html += f'<img src="data:image/png;base64,{plot_url}">'

        html += f"""
                </div>
                <div class="info-column">
                    <h3>内存使用情况</h3>
        """
        # 生成内存使用情况直方图
        labels = ['内存使用率', 'Swap 使用率']
        percentages = [memory_info['memory_usage_percentage'], memory_info['swap_usage_percentage']]

        fig, ax = plt.subplots(figsize=(5, 4))  # 适当调整图表大小
        ax.bar(labels, percentages, color='salmon')
        ax.set_xlabel('内存类型')
        ax.set_ylabel('使用率 (%)')
        ax.set_title(f'{host_name} 内存使用情况')
        ax.set_ylim(0, 100)

        img = BytesIO()
        plt.savefig(img, format='png', bbox_inches='tight')
        img.seek(0)
        plot_url = base64.b64encode(img.getvalue()).decode()

        html += f'<img src="data:image/png;base64,{plot_url}">'

        html += f"""
                </div>
                <div class="info-column">
                    <h3>CPU 使用情况</h3>
        """
        # 生成 CPU 使用情况直方图
        states = list(cpu_info.keys())
        percentages = list(cpu_info.values())

        fig, ax = plt.subplots(figsize=(5, 4))  # 适当调整图表大小
        ax.bar(states, percentages, color='orange')
        ax.set_xlabel('CPU 状态')
        ax.set_ylabel('使用率 (%)')
        ax.set_title(f'{host_name} CPU 使用情况')
        ax.set_ylim(0, 100)

        img = BytesIO()
        plt.savefig(img, format='png', bbox_inches='tight')
        img.seek(0)
        plot_url = base64.b64encode(img.getvalue()).decode()

        html += f'<img src="data:image/png;base64,{plot_url}">'

        html += """
                </div>
            </div>
        </div>
        """

    html += """
    </div>
</body>
</html>
"""
    return html


# ... 后面的代码保持不变 ...

# ... 前面的代码保持不变 ...

def generate_html(host_infos):
    """
    根据多个主机的存储、内存和 CPU 信息生成 HTML 文件
    :param host_infos: 包含多个主机信息的列表，每个元素是一个字典，包含主机名、存储信息、内存信息和 CPU 信息
    :return: HTML 内容
    """
    flush_interval = Env.get_flush_interval("storage")
    html = f"""
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="refresh" content="{flush_interval}">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>多服务器 Linux 存储、内存和 CPU 使用情况</title>
    <style>
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: #f4f4f9;
            margin: 20px;
        }}
        h1 {{
            text-align: center;
            color: #333;
            font-size: 24px;
            margin-bottom: 20px;
        }}
        .container {{
            display: flex;
            flex-direction: column;
            gap: 20px;
        }}
        .server-box {{
            background-color: #fff;
            border: none;
            border-radius: 8px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            padding: 20px;
            transition: box-shadow 0.3s ease;
        }}
        .server-box:hover {{
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
        }}
        h2 {{
            font-size: 20px;
            color: #333;
            margin-bottom: 15px;
        }}
        .info-container {{
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
        }}
        .info-column {{
            flex: 0 0 calc(50% - 40px); /* 两个一列，减去间距 */
            border: 1px solid #e0e0e0;
            border-radius: 4px;
            padding: 10px;
        }}
        h3 {{
            font-size: 16px;
            color: #555;
            margin-bottom: 10px;
        }}
        p {{
            font-size: 14px;
            color: #666;
            margin-bottom: 5px;
        }}
        img {{
            width: 100%;
            height: auto;
        }}
    </style>
</head>
<body>
    <h1>多服务器 Linux 存储、内存和 CPU 使用情况</h1>
    <div class="container">
    """

    for host_info in host_infos:
        host_name = host_info['host_name']
        storage_info = host_info['storage_info']
        memory_info = host_info['memory_info']
        cpu_info = host_info['cpu_info']

        html += f"""
        <div class="server-box">
            <h2>{host_name}</h2>
            <div class="info-container">
                <div class="info-column">
                    <h3>磁盘使用情况</h3>
        """
        # 生成磁盘使用情况直方图
        mount_points = [info['mount_point'] for info in storage_info]
        usage_percentages = [info['usage_percentage'] for info in storage_info]

        fig, ax = plt.subplots(figsize=(5, 4))  # 适当调整图表大小
        ax.bar(mount_points, usage_percentages, color='skyblue')
        ax.set_xlabel('挂载点', fontsize=10)
        ax.set_ylabel('使用率 (%)', fontsize=10)
        ax.set_title(f'{host_name} 磁盘使用情况')
        ax.set_ylim(0, 100)

        # 设置 x 轴和 y 轴刻度的字体大小
        ax.tick_params(axis='x', labelsize=8, rotation=45)
        ax.tick_params(axis='y', labelsize=10)

        img = BytesIO()
        plt.savefig(img, format='png', bbox_inches='tight')
        img.seek(0)
        plot_url = base64.b64encode(img.getvalue()).decode()

        html += f'<img src="data:image/png;base64,{plot_url}">'

        html += f"""
                </div>
                <div class="info-column">
                    <h3>内存使用情况</h3>
        """
        # 生成内存使用情况直方图
        labels = ['内存使用率', 'Swap 使用率']
        percentages = [memory_info['memory_usage_percentage'], memory_info['swap_usage_percentage']]

        fig, ax = plt.subplots(figsize=(5, 4))  # 适当调整图表大小
        ax.bar(labels, percentages, color='salmon')
        ax.set_xlabel('内存类型')
        ax.set_ylabel('使用率 (%)')
        ax.set_title(f'{host_name} 内存使用情况')
        ax.set_ylim(0, 100)

        img = BytesIO()
        plt.savefig(img, format='png', bbox_inches='tight')
        img.seek(0)
        plot_url = base64.b64encode(img.getvalue()).decode()

        html += f'<img src="data:image/png;base64,{plot_url}">'

        html += f"""
                </div>
                <div class="info-column">
                    <h3>CPU 使用情况</h3>
        """
        # 生成 CPU 使用情况直方图
        states = list(cpu_info.keys())
        percentages = list(cpu_info.values())

        fig, ax = plt.subplots(figsize=(5, 4))  # 适当调整图表大小
        ax.bar(states, percentages, color='orange')
        ax.set_xlabel('CPU 状态')
        ax.set_ylabel('使用率 (%)')
        ax.set_title(f'{host_name} CPU 使用情况')
        ax.set_ylim(0, 100)

        img = BytesIO()
        plt.savefig(img, format='png', bbox_inches='tight')
        img.seek(0)
        plot_url = base64.b64encode(img.getvalue()).decode()

        html += f'<img src="data:image/png;base64,{plot_url}">'

        html += """
                </div>
            </div>
        </div>
        """

    html += """
    </div>
</body>
</html>
"""
    return html


if __name__ == "__main__":
    scan()
